package cn.gz.ibix.library.http;

import com.google.common.collect.Maps;
import com.google.gson.Gson;

import java.io.IOException;
import java.util.Map;

import io.reactivex.Flowable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Function;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 项目名称：QiYiChuAPP
 * <br>类描述：
 * <br>创建人：htliu
 * <br>创建时间：2018/3/24 11:15
 * <br>修改人:
 * <br>修改时间：2018/3/24 11:15
 * <br>修改备注：
 * <br>@version
 */

public abstract class BaseHttpUtil implements IHttpUtil {
    private static final String TAG = "HttpUtil";
    private Gson gson = new Gson();


    protected abstract String getBaseUrl();

    protected abstract Map<String, String> headers();

    protected String getUrl(RequestParam requestParam) {
        return getBaseUrl() + requestParam.api();
    }

    @Override
    public void request(final RequestParam requestParam) {
        OkHttpClient client = getClient();
        Request.Builder builder = new Request.Builder();
        Map<String, String> headers = Maps.newHashMap(headers());
        if (validMap(requestParam.headers())) {
            headers.putAll(requestParam.headers());
        }
        builder.headers(Headers.of(headers));
        String url = getUrl(requestParam);
        if (validMap(requestParam.params())) {
            url += parseParam(requestParam.params());
        }
        builder = builder.url(url).method(requestParam.method().name(), getRequestBody(requestParam));
        final IConvertResponse iConvertResponse = requestParam.iConvertResponse();
        client.newCall(builder.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                if (iConvertResponse != null) {
                    iConvertResponse.onError(e);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (iConvertResponse != null) {
                    String body = response.body().string();
                    if (response.code() == 200) {
                        iConvertResponse.handle(body);
                    } else {
                        iConvertResponse.onFail(body);
                    }

                }
            }
        });
    }

    private RequestBody getRequestBody(RequestParam param) {
        if (param.method() == RequestParam.Method.GET) {
            return null;
        }
        RequestParam.UploadType type = param.uploadType();
        if (type == null) {
            return RequestBody.create(MediaType.parse("application/json"), "");
        }
        switch (type) {
            case BODY:
                if (param.bodyType().equals(RequestParam.BodyType.JSON)) {
                    return json(param.body());
                }
                break;
            case FORM:
                return form(param.forms());
            case FILE:
                // TODO: 2018/4/24
                break;
        }
        return null;
    }

    private RequestBody json(Object body) {
        String content = gson.toJsonTree(body).toString();
        return RequestBody.create(MediaType.parse("application/json"), content);
    }

    private RequestBody form(Map<String, String> forms) {
        FormBody.Builder formBuilder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : forms.entrySet()) {
            formBuilder.add(entry.getKey(), entry.getValue());
        }
        return formBuilder.build();
    }

    private String parseParam(Map<String, String> params) {
        String paramStr = Flowable.fromIterable(params.entrySet()).map(new Function<Map.Entry<String, String>, String>() {
            @Override
            public String apply(Map.Entry<String, String> entry) throws Exception {
                return entry.getKey() + "=" + entry.getValue();
            }
        }).reduce(new BiFunction<String, String, String>() {
            @Override
            public String apply(String s, String s2) throws Exception {
                return s + "&" + s2;
            }
        }).blockingGet("");
        return paramStr.length() > 0 ? "?" + paramStr : "";
    }

    private OkHttpClient getClient() {
        OkHttpClient okHttpClient = new OkHttpClient();
        // TODO: 2018/4/24 暂时没有设置复杂的，后期加上日志拦截，缓存，headers
        return okHttpClient;
    }

    /**
     * 检查map是否可用
     *
     * @param map
     * @return
     */
    private boolean validMap(Map map) {
        return map != null && !map.isEmpty();
    }

}
